#pragma once
#include "requestor.hpp"

namespace rpc
{
    namespace client
    {
        class Provider
        {
        public:
            using ptr = std::shared_ptr<Provider>;
            Provider(){}
            Provider(const Requestor::ptr &requestor)
                : _requestor(requestor)
            {}

            // 注册:连接，主机，方法：那个连接上的那台主机的方法
            bool onRegistry(const BaseConnection::ptr &conn, const std::string &method, Address &host)
            {
                // 构建注册请求
                delog("onRegistry开始注册方法"); 
                auto msg = MessageFactory::create<ServerRequest>();
                msg->setId(UUID::uuid());
                msg->setMethod(method);
                msg->setOptionType(SERVICE_TYPE::SERVICE_REGISTRY);
                msg->setHost(host);
                msg->setMytype(MY_TYPE::REQ_SERVICE);
                BaseMessage::ptr rsp_msg;
                bool ret = _requestor->send(conn, msg, rsp_msg);
                delog("onRegistry注册方法结束");
                if (!ret)
                {
                    errlog("requestor发送消息失败");
                    return false;
                }

                // 将rsp_msg转换升级
                auto service_msg = std::dynamic_pointer_cast<ServerResponse>(rsp_msg);
                if (!service_msg.get())
                {
                    errlog("service_msg类型转换失败");
                    return false;
                }

                if (service_msg->getRecode() != MY_CODE::RCODE_OK)
                {
                    errlog("消息响应类型失败");
                    return false;
                }
                delog("onRegistry注册成功");
                return true;
            }

        private:
            // 一个requestor对象:用来在客户端注册时发送请求
            Requestor::ptr _requestor;
        };

        class Method_hosts
        {
        public:
            using ptr = std::shared_ptr<Method_hosts>;
            Method_hosts():_index(0){}
            Method_hosts(const std::vector<Address> &hosts)
                : _hosts(hosts.begin(), hosts.end()), _index(0) {}
            // 添加主机地址
            void appendHost(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _hosts.push_back(host);
            }
            // 根据_index来选择，实现rr轮转
            Address choose()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                int pos = _index++ % _hosts.size();
                return _hosts[pos];
            }
            bool empty()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                return _hosts.empty();
            }

            // 根据host名来删除
            void remove(Address host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // 循环遍历查找到对应的迭代器
                for (auto it = _hosts.begin(); it != _hosts.end(); it++)
                {
                    if (*it == host)
                    {
                        _hosts.erase(it);
                        break;
                    }
                }
            }

        private:
            std::mutex _mutex;
            size_t _index = 0;
            std::vector<Address> _hosts;
        };

        class Discover
        {
        public:
            using offlineCallback = std::function<void(const Address &)>;
            using ptr = std::shared_ptr<Discover>;
            Discover(const Requestor::ptr requestor, const offlineCallback& offlinecb)
                : _requestor(requestor), _offlinecallback(offlinecb)
            {
            }

            // 根据服务的名称和主机找到服务
            bool serviceDiscovery(const BaseConnection::ptr &conn, const std::string &method, Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // 根据方法名字找服务主机
                auto it = _method_hosts.find(method);
                // 找到了服务主机就返回
                if (it != _method_hosts.end())
                {
                    delog("找到了主机");
                    host = it->second->choose();
                    delog("%s:%d", host.first.c_str(), host.second);
                    return true;
                }
                // 没找到：开始使用requstor来进行服务发现申请
                // 1,构造请求
                auto req = MessageFactory::create<ServerRequest>();
                req->setId(UUID::uuid());
                req->setMethod(method);
                req->setMytype(MY_TYPE::REQ_SERVICE);
                req->setOptionType(SERVICE_TYPE::SERVICE_DISCOVERY);
                BaseMessage::ptr rsp;
                bool ret = _requestor->send(conn, req, rsp);
                if (ret == false)
                {
                    errlog("服务发送失败");
                    return false;
                }

                // 得到回应后开始升级类型
                auto service_rsp = std::dynamic_pointer_cast<ServerResponse>(rsp);
                if(service_rsp.get() == nullptr)
                {
                    errlog("响应升级失败");
                    return false;
                }
                // 开始校验
                if (service_rsp->getRecode()!=MY_CODE::RCODE_OK)
                {
                    errlog("服务响应码异常，%s",ERR_RESON(service_rsp->getRecode()).c_str());
                    return false;
                }
                
                //响应成功，并且响应码也是对的
                //获取主机信息插入到_method_hosts中,并且从对应的方法中取出一个来提供服务
                auto method_host = std::make_shared<Method_hosts>(service_rsp->getHosts());
                if(method_host->empty())
                {
                    errlog("没有主机可以提供服务！");
                    return false;
                }
                host = method_host->choose();
                _method_hosts[method] = method_host;
                return true;
            }

            // 提供给dispacher模块的接口
            void onRequestor(const BaseConnection::ptr &conn, const ServerRequest::ptr &msg) 
            {
                //获取msg的类型
                auto type = msg->getOption();
                auto method = msg->getMethod();
                // 上线请求
                if(type == (int)SERVICE_TYPE::SERVICE_ONLINE)
                {
                    //找对应方法的主机序列
                    auto it = _method_hosts.find(method);
                    if(it!=_method_hosts.end())
                    {
                        //找到了就直接添加
                        it->second->appendHost(msg->getHost());
                        return;
                    }
                    else
                    {
                        //没找到就创建一个序列然后添加上去
                        auto method_hosts = std::make_shared<Method_hosts>();
                        method_hosts->appendHost(msg->getHost());
                        _method_hosts[method] = method_hosts;
                        return;
                    }
                }
                //下线请求
                else if(type == (int)SERVICE_TYPE::SERVICE_OFFLINE)
                {
                    auto it = _method_hosts.find(method);
                    if(it == _method_hosts.end())
                    {
                        return;
                    }
                    else
                    {
                        it->second->remove(msg->getHost());
                        _offlinecallback(msg->getHost());
                        return;
                    }
                }
            }

        private:
            offlineCallback _offlinecallback;
            std::mutex _mutex;
            // 选择host
            std::unordered_map<std::string, Method_hosts::ptr> _method_hosts;
            // requstor对象用来发送
            Requestor::ptr _requestor;
        };
    }
}